home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Internet PMSAM source / gatewayevents.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-29  |  13.6 KB  |  518 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------
  2.  
  3. AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
  4. Mail Service Access Module
  5.  
  6. written by Steve Falkenburg-- MacDTS
  7. ©1991-1993 Apple Computer, Inc.
  8.  
  9. --------------
  10. change history
  11. --------------
  12.  
  13. SJF        02/19/93    update for beta build    b1
  14. SJF        10/29/92    update to a11            a11
  15. SJF        06/08/92    update to a8            a8
  16. SJF        02/15/92    first working version    a4.5
  17. SJF        10/16/91    initial coding            a3
  18.  
  19. ---------------------------------------------------------------------*/
  20.  
  21. #ifndef __TYPES__
  22. #include <Types.h>
  23. #endif
  24.  
  25. #ifndef __PROCESSES__
  26. #include <Processes.h>
  27. #endif
  28.  
  29. #ifndef __OCE__
  30. #include <OCE.h>
  31. #endif
  32.  
  33. #ifndef __OCEERRORS__
  34. #include <OCEErrors.h>
  35. #endif
  36.  
  37. #include "const.h"
  38. #include "gwerrors.h"
  39. #include "mytypes.h"
  40. #include "globals.h"
  41. #include "utils.h"
  42. #include "gatewaystuff.h"
  43. #include "gatewayget.h"
  44. #include "gatewayput.h"
  45. #include "errorhandling.h"
  46.  
  47. #include "gatewayevents.h"
  48.  
  49.  
  50. // DoGatewayEvent
  51. //
  52. // handles high level events passed from the AOCE toolbox to the MSAM
  53. //
  54. // input: messageID       -- identifies the high level event
  55. //        mailEPPC        -- mail EPPC message area containing shared mem area and msg seq number
  56. //        slotID          -- slot ID (if used)
  57. //        inMainEventLoop -- true if we're being called from our main event loop
  58. //
  59. // on exit, the result field of the SMCA is set to the appropriate error code, indicating
  60. // that the MSAM is done processing the event
  61. //
  62. // note: I removed the EPPC handlers for MailboxOpened, MailboxClosed, and SendImmediate, as
  63. //       they are no longer of value to the MSAM
  64. //
  65. // note: only CreateSlot, ModifySlot, DeleteSlot and message opened EPPCs are reliable
  66. //       all others are informational only and may not always be sent (no guarantees)
  67. //
  68. // online gateway note: we do not handle  kMailEPPCMsgOpened
  69. //       since we are not an online gateway
  70. //
  71. OSErr DoGatewayEvent(long messageID,MailEPPCMsg *mailEPPC,short slotID,Boolean inMainEventLoop)
  72. {
  73.     OSErr err;
  74.     
  75.     err = noErr;
  76.     
  77.     switch (messageID) {
  78.  
  79.         // create a new slot
  80.         case kMailEPPCCreateSlot:
  81.             err = CreateSlot(gMSAMCID,mailEPPC->u.theSMCA->u.slotCID);
  82.             mailEPPC->u.theSMCA->result = err;
  83.             break;
  84.  
  85.         // modify the contents of an existing slot
  86.         case kMailEPPCModifySlot:
  87.             err = ModifySlot(gMSAMCID,GetSlotSpecFromID(slotID),mailEPPC->u.theSMCA->u.slotCID);
  88.             mailEPPC->u.theSMCA->result = err;
  89.             break;
  90.  
  91.         // delete an existing slot
  92.         case kMailEPPCDeleteSlot:
  93.             err = DeleteSlot(gMSAMCID,GetSlotSpecFromID(slotID));
  94.             mailEPPC->u.theSMCA->result = err;
  95.             break;
  96.  
  97.         // shut down the gateway
  98.         case kMailEPPCShutDown:
  99.             err = ShutDownServer();
  100.             break;
  101.  
  102.         // instructs the gateway to continue operation after previously suspending itself
  103.         case kMailEPPCContinue:
  104.             if (slotID==0)
  105.                 err = ContinueOperation(nil);
  106.             else
  107.                 err = ContinueOperation(GetSlotSpecFromID(slotID));
  108.             break;
  109.         
  110.         // informs a gateway that it's time to wake up (when a mail check timer expires)
  111.         case kMailEPPCSchedule:
  112.             if (inMainEventLoop)
  113.                 err = TimeToCheckForMail();
  114.             else {
  115.                 err = EnqueueHighLevelEvent(kMailEPPCSchedule,nil,slotID);
  116.             }
  117.             break;
  118.         
  119.         // instructs a gateway to update its incoming queue (for post-its)
  120.         //
  121.         // CHANGE NOTE: you have to handle this EPPC even if you're not online, since
  122.         // the appropriate action is to delete the message summary if the message is to be
  123.         // deleted or at least set the msgUpdated field to false.
  124.         //
  125.         case kMailEPPCInQUpdate:
  126.             if (inMainEventLoop)
  127.                 err = InQueueUpdate(mailEPPC->u.sequenceNumber,GetSlotSpecFromID(slotID),inMainEventLoop);
  128.             else {
  129.                 err = EnqueueHighLevelEvent(kMailEPPCInQUpdate,mailEPPC,slotID);
  130.             }
  131.             break;        
  132.         // instructs a gateway that a message was opened (for post-its)
  133.         case kMailEPPCMsgOpened:
  134.             mailEPPC->u.theSMCA->result = noErr;    // don't handle, since we're not online
  135.             break;
  136.         
  137.         // instructs a gateway to wake up due to an external event (something bad happened)
  138.         case kMailEPPCWakeup:
  139.             err = WakeupFromExternalEvent();
  140.             break;
  141.         
  142.         // notification that gateway has a letter in outgoing queue
  143.         case kMailEPPCMsgPending:
  144.             if (inMainEventLoop)
  145.                 err = MessagePending(GetSlotSpecFromID(slotID));
  146.             else {
  147.                 err = EnqueueHighLevelEvent(kMailEPPCMsgPending,nil,slotID);
  148.             }
  149.             break;
  150.  
  151.         // send the message without waiting for the schedule event
  152.         case kMailEPPCSendImmediate:
  153.             // should save away sequence number to send now
  154.             // also should force sending now…
  155.             mailEPPC->u.theSMCA->result = noErr;    // don't handle, since we're not online
  156.             break;
  157.  
  158.         // tells us that the user changed the location info in "I'm at"
  159.         case kMailEPPCLocationChanged:
  160.             err = ChangeLocation(GetSlotSpecFromID(slotID),&mailEPPC->u.locationInfo);
  161.             break;
  162.  
  163.         // these aren't handled
  164.         case kMailEPPCMailboxOpened:
  165.         case kMailEPPCMailboxClosed:
  166.         case kMailEPPCDeleteOutQMsg:
  167.             err = noErr;
  168.             break;
  169.             
  170.         // unsupported high level event
  171.         defaut:
  172.             err = kUndefinedHighLevelEvent;
  173.             break;
  174.     }
  175.             
  176.     return err;
  177. }
  178.  
  179.  
  180. OSErr EnqueueHighLevelEvent(long messageID,MailEPPCMsg *mailEPPC,short slotID)
  181. {
  182.     HLEventQ *newEl;
  183.     MailEPPCMsg *newEPPC;
  184.     
  185.     newEl = NewPtrChk(sizeof(HLEventQ));
  186.     if (MemError()!=noErr)
  187.         return MemError();
  188.     
  189.     newEPPC = NewPtrChk(sizeof(MailEPPCMsg));
  190.     if (MemError()!=noErr)
  191.         return MemError();
  192.     BlockMove(mailEPPC,newEPPC,sizeof(MailEPPCMsg));
  193.     
  194.     newEl->messageID = messageID;
  195.     newEl->mailEPPC = newEPPC;
  196.     newEl->slotID = slotID;
  197.             
  198.     newEl->next = gHLEventAdd;
  199.     newEl->prev = nil;
  200.     gHLEventAdd->prev = newEl;
  201.     gHLEventAdd = newEl;
  202.     if (gHLEventRemove==nil)
  203.         gHLEventRemove = newEl;
  204.  
  205.     return noErr;    
  206. }
  207.  
  208.  
  209. Boolean DequeueHighLevelEvent(long *messageID,MailEPPCMsg *mailEPPC,short *slotID)
  210. {
  211.     HLEventQ *oldQ;
  212.     
  213.     if (!gHLEventRemove)
  214.         return false;
  215.     
  216.     *messageID = gHLEventRemove->messageID;
  217.     BlockMove(gHLEventRemove->mailEPPC,mailEPPC,sizeof(MailEPPCMsg));
  218.     *slotID = gHLEventRemove->slotID;
  219.     
  220.     oldQ = gHLEventRemove;
  221.     gHLEventRemove = gHLEventRemove->prev;
  222.     if (gHLEventRemove)
  223.         gHLEventRemove->next = nil;
  224.     else
  225.         gHLEventAdd = nil;
  226.     
  227.     DisposPtrChk(oldQ);
  228.     
  229.     return true;
  230. }
  231.  
  232.  
  233. OSErr ProcessQueuedEvents(void)
  234. {
  235.     long messageID;
  236.     MailEPPCMsg mailEPPC;
  237.     short slotID;
  238.     OSErr err;
  239.     
  240.     err = noErr;
  241.     while (DequeueHighLevelEvent(&messageID,&mailEPPC,&slotID) && err==noErr) {
  242.         err = DoGatewayEvent(messageID,&mailEPPC,slotID,true);
  243.     }
  244.     return err;
  245. }
  246.  
  247.  
  248. // CreateSlot
  249. //
  250. // high level call to process the Create Slot high level event
  251. //
  252. // inputs: msamCID      -- creation ID of the MSAM setup record
  253. //         slotCID      -- creation ID of the new slot information
  254. //
  255. OSErr CreateSlot(CreationID msamCID,CreationID slotCID)
  256. {
  257.     #pragma unused (msamCID)
  258.     OSErr err;
  259.     short slotID;
  260.     
  261.     TraceExecution("\pCreateSlot");
  262.     
  263.     // add SlotID to mailservice record
  264.     
  265.     slotID = 1;    // we only have 1 slot for now, so it is always ID 1
  266.     
  267.     err = AddAttribute(&slotCID,gAOCESetupDSRef,OCEGetIndAttributeType(kSlotIDAttrTypeNum),
  268.                     &slotID,sizeof(short),typeBinary);
  269.     if (err!=noErr)
  270.         return err;
  271.     
  272.     MarkSlotInformationDirty();    // mark that slots need to be updated at main event time
  273.     return noErr;
  274. }
  275.  
  276.  
  277. // ModifySlot
  278. //
  279. // high level call to process the Modify Slot high level event
  280. //
  281. // inputs: msamCID      -- creation ID of the MSAM setup record
  282. //         slot         -- slot specifier for the slot being modified
  283. //         slotCID      -- creation ID of the modified slot information
  284. //
  285. OSErr ModifySlot(CreationID msamCID,SlotSpec *slot,CreationID slotCID)
  286. {
  287.     #pragma unused (msamCID,slot,slotCID)
  288.     
  289.     TraceExecution("\pModifySlot");
  290.     
  291.     MarkSlotInformationDirty();    // mark that slots need to be updated at main event time
  292.     return noErr;
  293. }
  294.  
  295.  
  296. // DeleteSlot
  297. //
  298. // high level call to process the Delete Slot high level event
  299. //
  300. // inputs: msamCID      -- creation ID of the MSAM setup record
  301. //         slot         -- slot specifier for the slot being deleted
  302. //
  303. OSErr DeleteSlot(CreationID msamCID,SlotSpec *slot)
  304. {
  305.     PackedRecordID packedAssocDir;
  306.     AttributeCreationID attrCID;
  307.     CreationID foundCID,*dirCID;
  308.     AttributeCopyInfo attrInfo;
  309.     OSErr err;
  310.     
  311.     #pragma unused(msamCID)
  312.  
  313.     TraceExecution("\pDeleteSlot");
  314.     
  315.     // ***NOTE***:
  316.     //
  317.     // we have to delete the entry we placed in the "aoce Directories" attribute in the setup
  318.     // template at this point, since the system won't do it for us...
  319.     
  320.     // get associated directory creation ID
  321.     
  322.     err = GetSingleValueAttribute(&slot->slotCID,OCEGetIndAttributeType(kAssoDirectoryAttrTypeNum),
  323.             &packedAssocDir,sizeof(PackedRecordID));
  324.     if (err!=noErr)
  325.         return err;
  326.  
  327.     // find directory CID value in oce setup directories attribute
  328.     
  329.     attrInfo.buffer = (Ptr)&packedAssocDir;
  330.     attrInfo.bufferSize = packedAssocDir.dataLength + sizeof(short);
  331.     err = GetParseAttributes(&gAOCESetupCID,kDirectoriesAttrTypeNum,SearchCallback,(long)&attrInfo);
  332.     if (err!=noErr)
  333.         return err;
  334.     
  335.     // delete this stray attribute
  336.     
  337.     err = DeleteSingleAttributeValue(&gAOCESetupCID,OCEGetIndAttributeType(kDirectoriesAttrTypeNum),
  338.                                     &attrInfo.cid);
  339.     if (err!=noErr)
  340.         return err;
  341.  
  342.     // don't mark slots dirty, since we're about to reboot
  343.     // instead set the # of slots to 0 and prepare to quit
  344.     gNumSlots = 0;
  345.  
  346.     return noErr;
  347. }
  348.  
  349.  
  350. // ShutDownServer
  351. //
  352. // high level call to process the ShutDownServer high level event
  353. // sets gDone to true, indicating that we'll quit the next time through our event loop
  354. //
  355. OSErr ShutDownServer(void)
  356. {
  357.     TraceExecution("\pShutDownServer");
  358.     
  359.     gDone = true;
  360.     return noErr;
  361. }
  362.  
  363.  
  364. // MessagePending
  365. //
  366. // high level call to process the MessagePending high level event.
  367. // increments the number of messages pending counter on the slot the message is pending for.
  368. //
  369. OSErr MessagePending(SlotSpec *slot)
  370. {
  371.     OSErr err;
  372.     
  373.     TraceExecution("\pMessagePending");
  374.     
  375.     // if the slot isn't suspended, do the send now
  376.     
  377.     if (slot && slot->enabled) {
  378.         err = DoSlotGet(slot);
  379.         if (err!=noErr)
  380.             err = RetrySlotError(err,slot,false);
  381.     }
  382.     
  383.     return err;
  384. }
  385.  
  386.  
  387. // ContinueOperation
  388. //
  389. // process continue high level event, which instructs a gateway to continue operation after
  390. // previously suspending itself.  it's permissible to have a gateway quit itself between
  391. // transactions.  if this is done, each time the gateway is launched, it will get a
  392. // continue eppc.
  393. //
  394. // input:    slot    contains the slot specification for the slot being resumed, or nil of
  395. //                    the continue applies to the entire gateway.
  396. //
  397. OSErr ContinueOperation(SlotSpec *slot)
  398. {
  399.     TraceExecution("\pContinueOperation");
  400.     
  401.     if (slot)
  402.         slot->enabled = true;
  403.         
  404.     return noErr;
  405. }
  406.  
  407.  
  408. // TimeToCheckForMail
  409. //
  410. // process schedule high level event, which is sent by the toolbox when the check for mail
  411. // timers specified in the slot configuration records expire.  this event makes it so the
  412. // gateway doesn't continually have to poll to see if the checking timers have expired
  413. //
  414. OSErr TimeToCheckForMail(void)
  415. {
  416.     OSErr err,err2;
  417.     
  418.     TraceExecution("\pTimeToCheckForMail");
  419.     
  420.     // do gets/puts for slots whose timers have expired
  421.     
  422.     err = PeriodicCheckGet();
  423.     err2 = PeriodicCheckPut();
  424.     
  425.     if (err==noErr)
  426.         err = err2;
  427.         
  428.     return err;
  429. }
  430.  
  431.  
  432. // InQueueUpdate
  433. //
  434. // process in queue update high level event which is sent by the toolbox to mark a message
  435. // read or to delete a message.  this is mostly for on-line gateways, but we still need to
  436. // process it in our on-demand gateway, since the toolbox requires specific actions in response
  437. // to this event.
  438. //
  439. // we need to check the message summary for the message in question, and see if the msgDeleted
  440. // flag is true.  if so, we should delete the message summary for the message.
  441. //
  442. // if not a delete, we need to set the msgUpdated field to false to indicate that we've 
  443. // processed this event.
  444. //
  445. OSErr InQueueUpdate(long seqNum,SlotSpec *slot,Boolean inMainLoop)
  446. {
  447.     MSAMParam gwp;
  448.     MSAMMsgSummary msgSummary;
  449.     OSErr err;
  450.     
  451.     TraceExecution("\pInQueueUpdate");
  452.  
  453.     if (!slot)
  454.         return noErr;
  455.     
  456.     // get the message summary for the letter in question
  457.     
  458.     gwp.header.ioCompletion = (ProcPtr)MSAMCompletion;
  459.     gwp.pmsamGetMsgSummary.inQueueRef = slot->inQueue;
  460.     gwp.pmsamGetMsgSummary.seqNum = seqNum;
  461.     gwp.pmsamGetMsgSummary.msgSummary = &msgSummary;
  462.     gwp.pmsamGetMsgSummary.buffer = nil;
  463.     gwp.pmsamGetMsgSummary.msgSummaryOffset = 0;
  464.     err = PMSAMGetMsgSummary(&gwp,false);    // changed from async to avoid re-entrancy problems
  465.     if (err!=noErr)
  466.         return err;
  467.     
  468.     // if the letter is marked for deletion, then delete the message summary
  469.     
  470.     if (msgSummary.msgDeleted) {
  471.         gwp.msamDelete.queueRef  = slot->inQueue;
  472.         gwp.msamDelete.seqNum = seqNum;
  473.         gwp.msamDelete.msgOnly = false;
  474.         gwp.msamDelete.result = noErr;
  475.         err = MSAMDelete(&gwp,false);    // changed from async to avoid re-entrancy problems
  476.     }
  477.     
  478.     // otherwise, set the message summary msgUpdated flag to false
  479.     else {
  480.         msgSummary.msgUpdated = false;
  481.         err = PMSAMPutMsgSummary(&gwp,false);
  482.     }
  483.     
  484.     return err;
  485. }
  486.  
  487.  
  488. // ChangeLocation
  489. //
  490. // refreshes the location settings and location activation settings for
  491. // the gateway's slots.  this info is changed when the user chooses
  492. // "i'm at" from the Finder
  493. //
  494. OSErr ChangeLocation(SlotSpec *slot,MailLocationInfo *locationInfo)
  495. {
  496.     TraceExecution("\pChangeLocation");
  497.     
  498.     gLocation = locationInfo->location;
  499.     slot->locationActive = locationInfo->active;
  500.     return noErr;
  501. }
  502.  
  503.  
  504. // WakeupFromExternalEvent
  505. //
  506. // process the wakeup high level event, which instructs a gateway to wake up due to
  507. // an external event that cannot be predicted by AOCE  if a gateway receives an
  508. // eppcWakeup event just after being launched, it syhould take that to mean that it
  509. // was launched in response to an external event.  if the gateway was al;ready running
  510. // when the event arrived, it is an indication that ian external event important to the 
  511. // gateway has occured.  the wakeup attempt is not reliable
  512. //
  513. OSErr WakeupFromExternalEvent(void)
  514. {
  515.     TraceExecution("\pWakeupFromExternalEvent");
  516.     return noErr;
  517. }
  518.